package com.grt.condify.utils;


/**
 * Created by cy on 2015/8/29.
 * <p>
 * 帮助类或方法检查参数是否为空，是否满足指定的条件。所有方法都是静态方法
 *
 * @author cy
 */
public final class PreConditionCheck {

    private PreConditionCheck() {
    }

    /**
     * 确定传入内容是一个非空的对象，如果为空，将抛出NullPointerException
     *
     * @param content 验证对象
     * @return 返回经验证的非空对象
     * @throws NullPointerException 当对象为空，则抛出该异常
     */
    public static <T> T checkNotNull(T content) {
        return checkNotNull(content, new NullPointerException());
    }

    /**
     * 确定传入内容是一个非空的对象，如果为空，将抛出NullPointerException
     *
     * @param content  验证对象
     * @param errorMsg 错误信息，错误信息是直接通过String.valueOf方式进行转换
     * @return 返回经验证的非空对象
     * @throws NullPointerException 当前对象为空，则抛出该异常
     */
    public static <T> T checkNotNull(T content, Object errorMsg) {
        return checkNotNull(content, new NullPointerException(String.valueOf(errorMsg)));
    }

    /**
     * 确定传入内容是一个非空的对象，如果为空，将抛出NullPointerException
     * {@code errorMsgTemplate}包含了若干{@code %s}组成，这些都会被指定的{@code errorMsg}的内容所替换。例如：
     * {@code errorMsgTemplate}为：错误信息为%s,请注意修改；{@code errorMsg}为：空指针，则会被替换为：错误信息为空指针,请注意修改
     *
     * @param content          验证对象
     * @param errorMsgTemplate 错误信息模板，模板使用%s表示需要被错误信息替换的占位符
     * @param errorMsgs        错误信息内容
     * @return 返回经验证的非空对象
     * @throws NullPointerException 当前对象为空，则抛出该异常
     */
    public static <T> T checkNotNull(T content, String errorMsgTemplate, Object... errorMsgs) {
        return checkNotNull(content, new NullPointerException(format(errorMsgTemplate, errorMsgs)));
    }

    /**
     * 确定传入内容是一个非空的对象，如果为空，将抛出用户传入的异常<BR>
     *
     * @param content 验证对象
     * @param err     向上抛出的异常对象
     * @return 返回经验证的非空对象
     * @throws E 当前对象为空，则抛出该异常
     * @author 作者: chu.chuanbao E-mail: chu.chuanbao@trs.com.cn<br/>
     * 创建时间：2021/9/26 21:27
     */
    public static <T, E extends Throwable> T checkNotNull(T content, E err) throws E {
        if (content == null) {
            throw err;
        }
        return content;
    }

    /**
     * 确保传入的字符串非空，否则将抛出错误的异常
     *
     * @param string 字符串内容
     * @throws NullPointerException 当传入的是非值为false时，将导致异常
     */
    public static void checkNotEmpty(String string) {
        checkNotEmpty(string, new NullPointerException());
    }

    /**
     * 确保传入的字符串非空，否则将抛出错误的异常
     *
     * @param string   字符串内容
     * @param errorMsg 错误提示信息
     * @throws NullPointerException 当传入的是非值为false时，将导致异常
     */
    public static void checkNotEmpty(String string, String errorMsg) {
        checkNotEmpty(string, true, errorMsg);
    }

    /**
     * 确保传入的字符串非空，否则将抛出错误的异常
     *
     * @param string   字符串内容
     * @param errorMsg 错误提示信息
     * @param trim     是否修剪空格字符串
     * @throws NullPointerException 当传入的是非值为false时，将导致异常
     */
    public static void checkNotEmpty(String string, boolean trim, String errorMsg) {
        checkNotEmpty(string, trim, new NullPointerException(errorMsg));
    }


    public static <E extends Throwable> void checkNotEmpty(String string, E err) throws E {
        checkNotEmpty(string, true, err);
    }

    public static <E extends Throwable> void checkNotEmpty(String string, boolean trim, E err) throws E {
        if (string == null) {
            throw err;
        }
        if (trim) {
            string = string.trim();
        }
        if (string.length() == 0) {
            throw err;
        }
    }

    /**
     * 确保传入的是非判断为true，否则将抛出错误的异常
     *
     * @param expression 是非表达式
     * @throws IllegalArgumentException 当传入的是非值为false时，将导致异常
     */
    public static void checkArgument(boolean expression) {
        checkArgument(expression, new IllegalArgumentException());
    }

    /**
     * 确保传入的是非判断为true，否则将抛出错误的异常
     *
     * @param expression 是非表达式
     * @param errorMsg   错误信息
     * @throws IllegalArgumentException 当传入的是非值为false时，将导致异常
     */
    public static void checkArgument(boolean expression, Object errorMsg) {
        checkArgument(expression, new IllegalArgumentException(String.valueOf(errorMsg)));
    }

    public static void checkArgument(boolean expression, String errorMsgTemplate, Object... errorMsgs) {
        checkArgument(expression, new IllegalArgumentException(format(errorMsgTemplate, errorMsgs)));
    }

    public static <E extends Throwable> void checkArgument(boolean expression, E err) throws E {
        if (!expression) {
            throw err;
        }
    }

    static String format(String errorMsgTemplate, Object... errorMsg) {
        int i = 0;
        StringBuilder strBuilder = new StringBuilder();
        int templateCurrentIndexPos = 0;
        while (i < errorMsg.length) {
            int placeholderStartPos = errorMsgTemplate.indexOf("%s");
            if (placeholderStartPos == -1) {
                break;
            }
            strBuilder.append(errorMsgTemplate.substring(0, placeholderStartPos))
                    .append(errorMsg[i++]);
            templateCurrentIndexPos = placeholderStartPos + 2;
            errorMsgTemplate = errorMsgTemplate.substring(templateCurrentIndexPos);
        }
        //finish the replace of whole template
        strBuilder.append(errorMsgTemplate);

        //if errorMsg.length lgt placeholder of error message template, just append them in extra square braces
        if (i < errorMsg.length) {
            strBuilder.append("[");
            strBuilder.append(errorMsg[i++]);
            while (i < errorMsg.length) {
                strBuilder.append(",").append(errorMsg[i++]);
            }
            strBuilder.append("]");
        }
        return strBuilder.toString();
    }
}
